//////////////////////////////////////////////////////////////////////////////
//																			//
//  Filename:    RealmOfRichesGuts.cpp										//
//  Developer:   Ryan Sauls													//
//  Create date: 1/12/2006													//
//																			//
//////////////////////////////////////////////////////////////////////////////
//																			//
//  Description: This is the class implementation for the slot gut of the	//
//               Australian Slot machine called Realm Of Riches.			//
//																			//
//////////////////////////////////////////////////////////////////////////////
//        Copyright (c) 2006 - Realtime Gaming.  All rights reserved.		//
//////////////////////////////////////////////////////////////////////////////

#include ".\realmofrichesguts.h"


////////////////////////////////////////////////////////////////////////////
/// RealmOfRichesGuts::m_aLineWinSpinResults
///
/// This array is used to quickly get the SpinResult for the number of
/// icons.  It is indexed by wheel icon and then count.  So to get the
/// SpinResult for 5 Nine, use the following code snippet:
///
///		SpinResult result = m_aLineWinSpinResults[ ICON_NINE ][ 5 ];
///
/// In this example result would be set to EVT_FIVE_NINE.
////////////////////////////////////////////////////////////////////////////
RealmOfRichesGuts::SpinResult RealmOfRichesGuts::m_aLineWinSpinResults[NUM_VALID_ICONS][6] = 
{
// Number of icons:  0				1			2				3					4				5
/* ICON_NINE */		{ EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_THREE_NINE,		EVT_FOUR_NINE,	EVT_FIVE_NINE},
/* ICON_TEN */		{ EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_THREE_TEN,		EVT_FOUR_TEN,	EVT_FIVE_TEN},
/* ICON_JACK */		{ EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_THREE_JACK,		EVT_FOUR_JACK,	EVT_FIVE_JACK},
/* ICON_QUEEN */	{ EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_THREE_QUEEN,	EVT_FOUR_QUEEN,	EVT_FIVE_QUEEN},
/* ICON_KING */		{ EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_THREE_KING,		EVT_FOUR_KING,	EVT_FIVE_KING},
/* ICON_ACE */		{ EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_THREE_ACE,		EVT_FOUR_ACE,	EVT_FIVE_ACE},
/* ICON_TOWER */	{ EVT_LOSER,	EVT_LOSER,	EVT_TWO_TOWER,	EVT_THREE_TOWER,	EVT_FOUR_TOWER,	EVT_FIVE_TOWER},
/* ICON_HELMET */	{ EVT_LOSER,	EVT_LOSER,	EVT_TWO_HELMET,	EVT_THREE_HELMET,	EVT_FOUR_HELMET,EVT_FIVE_HELMET},
/* ICON_KNIGHT */	{ EVT_LOSER,	EVT_LOSER,	EVT_TWO_KNIGHT,	EVT_THREE_KNIGHT,	EVT_FOUR_KNIGHT,EVT_FIVE_KNIGHT},
/* ICON_WOMAN */	{ EVT_LOSER,	EVT_LOSER,	EVT_TWO_WOMAN,	EVT_THREE_WOMAN,	EVT_FOUR_WOMAN,	EVT_FIVE_WOMAN},
/* ICON_SHIELD */	{ EVT_LOSER,	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,			EVT_LOSER,		EVT_LOSER},
/* ICON_CROWN */	{ EVT_LOSER,	EVT_LOSER,	EVT_TWO_CROWN,	EVT_THREE_CROWN,	EVT_FOUR_CROWN,	EVT_FIVE_CROWN}
};

////////////////////////////////////////////////////////////////////////////
/// RealmOfRichesGuts::m_aScatterWinSpinResults
///
/// This array is used to quickly get the SpinResult for the number of
/// icons.  It is indexed by icon count only, since Shield is the only
/// scatter win.  So to get the SpinResult for 5 Shield, use the
/// following code snippet:
///
///		SpinResult result = m_aScatterWinSpinResults[ 5 ];
///
/// In this example result would be set to EVT_FIVE_SHIELD.
////////////////////////////////////////////////////////////////////////////
RealmOfRichesGuts::SpinResult RealmOfRichesGuts::m_aScatterWinSpinResults[6] = 
{
	// Result			    Number of Icons
	EVT_LOSER,			    // 0
	EVT_SCATTER_NEAR_MISS,  // 1
	EVT_TWO_SHIELD,		    // 2
	EVT_THREE_SHIELD,	    // 3
	EVT_FOUR_SHIELD,	    // 4
	EVT_FIVE_SHIELD		    // 5
};

/******************************************************************************
Constructor/Destructor
******************************************************************************/

RealmOfRichesGuts::RealmOfRichesGuts(void)
{
	// If this doesn't compile it means that someone probably added
	// another icon type but did not update the
	// m_aLineWinSpinResults array. 
	C_ASSERT( countof( m_aLineWinSpinResults ) == NUM_VALID_ICONS );

	// Don't allow the guts to tell about our "fake" crown icons yet.
	m_bAllowCrownSubstitutions = false;
}

RealmOfRichesGuts::~RealmOfRichesGuts(void)
{
    deallocateCrownSubstitutionIcons();
}

/******************************************************************************
@fn RealmOfRichesGuts::load

@brief Override of the SlotGuts::load framework function.
       Allocates our map of substitution icons for use in the free game.
******************************************************************************/
bool8 
RealmOfRichesGuts::load(Info *info)
{
	// do base class load, and take the opportunity now to 
	// load up the substiution icons,
    return super::load( info ) && allocateCrownSubstitutionIcons();
}

/******************************************************************************
@fn RealmOfRichesGuts::allocateSubGameData()

@brief Override of the SlotGuts::allocateSubGameData framework function.
       Overridden to initialize the crown substitution positions.
******************************************************************************/
void 
RealmOfRichesGuts::allocateSubGameData()
{
	super::allocateSubGameData();
	
	// Reset to initialize...
	resetFreeSpinCrownSubstitutions();	
}

/******************************************************************************
@fn RealmOfRichesGuts::allocateCrownSubstitutionIcons()
@brief  Examines each SlotReel for the free game mode, and makes icons that
        can be passed from the override getIcon() method when the crown icon
        has expanded to cover all three rows of the reel.
        NOTE - this implementation assumes that the base class won't destroy
        the wheelhouse once it's been loaded!
******************************************************************************/
bool8
RealmOfRichesGuts::allocateCrownSubstitutionIcons()
{
    const SlotReel * pReel = NULL;

    //Go through each reel for the free spin mode and
    //make copies of the icons that could get substituted.
    //Change them so they LOOK like crowns
    for( uint8 reel = 0 ; reel < getReelCount() ; ++reel )
    {
        pReel = getSlotReel( MODE_FREE_SPIN, reel );

        for( SlotReel::const_iterator begin( pReel->begin() ), current( pReel->begin() ), end( pReel->end() );
             current != end;
             ++current )
             {
                 if ( (*current)->iconid == ICON_CROWN )
                 {
                     //Map the previous one or two icons to a substitution icon
                     if( distance (begin, current) >  1 )
                     {
                         // Copy & map the previous icon
                         SlotReel::const_iterator previous = current - 1;

                         addSubstitutionIcon( *previous );

                         // And the previous one, too, if there's one there
                         if ( distance( begin, previous ) > 2 )
                         {
                             addSubstitutionIcon( *--previous );

                         }
                     }

                     //Map the next one or two icons to a substitution icon
                     if ( distance( current, end ) > 1 )
                     {                         
                         // Copy & map the next icon
                         SlotReel::const_iterator next = current + 1;

                         addSubstitutionIcon( *next );

                         if( distance( current, end ) > 2 )
                         {
                             addSubstitutionIcon( *++next );
                         }
                     }
                 }
             }
    }

    return true;
}

/******************************************************************************
Function name	: RealmOfRichesGuts::deallocateCrownSubstitutionIcons
@brief	        Clean up our icons substitution map
@return	void 
******************************************************************************/
void RealmOfRichesGuts::deallocateCrownSubstitutionIcons()
{
    //Clean up our substitution map
    for( SlotIconSubstitutionMap::iterator current( m_mapSubstitutionIcons.begin() ), end( m_mapSubstitutionIcons.end() );
            current != end;
            ++current )
            {
                delete current->second;
            }
}

/******************************************************************************
Function name	: RealmOfRichesGuts::addSubstitutionIcon
@brief	 Adds an icon duplicating the passed icon, except with the iconid
        set to ICON_CROWN, for use in the getIcon() method during free games.
@return	void  
@param	const SlotIcon* icon - the icon to copy and key against in the new mapping.
******************************************************************************/
void  RealmOfRichesGuts::addSubstitutionIcon( const SlotIcon* icon)
{
    // Map this icon to a substitution icon
    // Copy the supplied icon
    SlotIcon* subicon = new SlotIcon( *icon );

    // Fix up its iconid
    subicon->iconid = ICON_CROWN;
    
    // Map it back to the real iterator for later.
    VERIFY( m_mapSubstitutionIcons.insert( make_pair( icon, subicon ) ).second );
}

/******************************************************************************
Function name	: RealmOfRichesGuts::getIcon
@brief	Returns the SlotIcon for the specified gamemode, reel and position.
        If free games mode is active and any icon on the reel is a Crown, the
        "real" returned icon is replace with a copy of it having the ICON_CROWN iconid.
@return	const SlotIcon* - the icon for this gamemode, reel, and position
@param		uint8 gamemodeID
@param		uint8 reelID
@param		uint8 position
******************************************************************************/
const SlotIcon* RealmOfRichesGuts::getIcon( uint8 gamemodeID, uint8 reelID, uint8 position ) const
{
    const SlotIcon* pRealIcon = super::getIcon( gamemodeID, reelID, position );

    //If this reel has an active crown substitution, then return our mocked up icon
    //that looks like a crown.
    if ( m_bAllowCrownSubstitutions
		&& gamemodeID == MODE_FREE_SPIN 
        && ICON_CROWN != pRealIcon->iconid 
        && -1 != getFreeSpinCrownSubstitution( reelID ) )
    {
        SlotIconSubstitutionMap::const_iterator substitute = m_mapSubstitutionIcons.find(pRealIcon);

        //If this is a stop than can be substituted with a Crown in free spin mode,
        //return the duplicate Crown icon.
        if( substitute != m_mapSubstitutionIcons.end() )
        {
            return substitute->second;
        }
    }
    return pRealIcon;
}

void RealmOfRichesGuts::classifyStops( SpinLine* spinLine, uint8* stops, uint8 bet, uint8 line,
														uint8& rtnResult, uint8 &multiplier )
{
	// If we are in re-spin mode...
	if ( getGameModeId() == MODE_RESPIN )
	{
		// then we don't allow line wins.
		rtnResult = EVT_LOSER;

		// Exit out early.
		return;
	}

	// Track the Crown result separately since it might be changed to a substitution.
	SpinResult srCrownLineWinResult = getCrownLineWinResult( stops );

	// Now see what the payout is if we use any Crowns we find as substitution symbols.
	// Start with the icon on the first reel.
	uint8 testIcon = getIcon( getGameModeId(), 0, stops[0] )->iconid;

	// Declare a local variable to track whether or not we found a substitution.
	bool bSubstitution = false;

	// See what the spin result is if we used any Crowns as substitution symbols.
	SpinResult srResultWithPossibleSubstitution =
		getLineWinResultWithPossibleSubstitution( stops, testIcon, bSubstitution );

	// Use the larger payout between the regular Crown evaluation compared to
	// the evaluation with the possible substitution.
    if ( doesCrownLineWinPayMore( srCrownLineWinResult,
		srResultWithPossibleSubstitution ) )
	{
		// The Crowns by themselves pay out more so use the Crown result.
		rtnResult = srCrownLineWinResult;
	}
	else
	{
		// Otherwise the result with the substitution (if any) paid more so use it.
		rtnResult = srResultWithPossibleSubstitution;

		// If we did actually have a substitution and a winning spin...
		if ( bSubstitution && srResultWithPossibleSubstitution != EVT_LOSER )
		{
			// then add a note.
			spinLine->addNote( NOTE_CROWN_SUBSTITUTION );
		}
	}
}

void RealmOfRichesGuts::classifyScatters( SlotSpin* spin )
{
	// Try for the Random Progressive Jackpot
	tryForJackpot( spin );

	// Declare a local variable to track the scatter positions.
	int32 nScatterPositions = 0;

	// See if there is a scatter.
	SpinResult srResult = getScatterWinResult( spin, nScatterPositions );

	// Add the scatter, if any.
	evaluateScatterWin( spin, srResult, nScatterPositions );

	// See if we triggered the free game feature.
	evaluateFeatureTrigger( spin, srResult, nScatterPositions );
}

void RealmOfRichesGuts::tryForJackpot( SlotSpin* spin )
{
	// If we are in the first paid spin (NOT a bonus spin)...
	if ( getGameModeId() == MODE_NORMAL ) 
	{
		// then try for the Random Progressive Jackpot
		// If we hit the jackpot...
		if ( getRandomProgressiveJackpotResult( spin->getSpinLineCount() ) || 
			m_bForceRandomJackpot==true)
		{
			// then add a jackpot scatter to the spin.
			spin->addScatter( 0,
				getPayout( EVT_RANDOM_PROGRESSIVE_WINNER )->payoutAmount, 1,
				true, EVT_RANDOM_PROGRESSIVE_WINNER, 0 );
		}
    }
}


RealmOfRichesGuts::SpinResult RealmOfRichesGuts::getScatterWinResult( SlotSpin* spin, int32& scatterPositions ) const
{
	// Declare a local variable to keep up with the icon count.
	uint8 numScatterIcons = 0;

	// Initialize the scatterPositions.
	scatterPositions = 0;

	// Loop through each reel.
  	for( int reel = 0; reel < getReelCount(); reel++ )
	{
		// The position bit for the current icon in case it needs to be stored in a mask.
		uint8 position = reel;

		// Keep up with whether or not we find an icon on this reel
		bool bFoundScatterIconOnReel = false;

		// Loop through each row in the wheel house.
		for( int row = 0; row < 3; row++ )
		{
			// Get the current stop.
			uint8 stop = relativeWheelPosition( getGameModeId(), reel,
				spin->getStops()[ reel ], row );

			// Get the icon for the current stop.
			uint8 currentIcon = getIcon( getGameModeId(), reel, stop )->iconid;
			
			// If the icon is the one we are looking for...
			if ( currentIcon == ICON_SHIELD )
			{
				// then increase the icon count
				numScatterIcons++;

				// Set the bit in the position mask for this stop.
				scatterPositions |= 1 << position;

				// We found a scatter icon.
				bFoundScatterIconOnReel = true;
			}

			// Move to the next bit in the position mask.
            position += 5;
		}

		// If we didn't find a scatter icon on the reel...
		if ( !bFoundScatterIconOnReel )
		{
			// then we are done since this game pays left to right for
			// scatters, instead of any.
			break;
		}
	}

	return lookupScatterWinSpinResult( numScatterIcons );
}


bool8 RealmOfRichesGuts::isValidGuts()
{
	return MIN <= getGutsId() && getGutsId() < MAX ;
}


void RealmOfRichesGuts::getGameModeMultiplierAndNoteId(uint8& nGameModeMultiplier, uint8 &nNoteId)
{
	// If we are in free spin mode...
    if ( getGameModeId() == MODE_FREE_SPIN )
    {
		// then return the free spin multiplier...
        nGameModeMultiplier = MULTIPLIER_FREE_SPIN;

		// and the free spin note.
        nNoteId = NOTE_FREE_SPIN;
    }
	// Otherwise...
    else
    {
		// just defer to the base class.
        SlotGuts::getGameModeMultiplierAndNoteId( nGameModeMultiplier, nNoteId );
    }
}

RealmOfRichesGuts::SpinResult RealmOfRichesGuts::getCrownLineWinResult( uint8* stops ) const
{
	// Count how many Crowns we have at the beginning of the line.
	uint8 i;

	for ( i = 0; i < getReelCount(); i++ )
    {
		// If this icon is not a Crown...
		if ( getIcon( getGameModeId(), i, stops[i] )->iconid != ICON_CROWN )
		{
            // then we have our total.
            break;
		}
    }

	// Use the array to look up the spin result for i Crowns.
	return lookupLineWinSpinResult( ICON_CROWN, i );
}

RealmOfRichesGuts::SpinResult RealmOfRichesGuts::getLineWinResultWithPossibleSubstitution(
	uint8* stops, uint8 testIcon, bool& bSubstitution ) const
{
	// Initialize the out parameter
	bSubstitution = false;
    
	// Loop through the remaining reels until the streak is over
	int i;

	for ( i = 0; i < getReelCount(); i++ )
    {
		// See what this icon is.
		uint8 currentIcon = getIcon( getGameModeId(), i, stops[i] )->iconid;

		// If the current icon is a Crown...
		if ( currentIcon == ICON_CROWN )
		{
			// then use it as a substitution symbol and continue on.
			bSubstitution = true;
			continue;
		}
		// Otherwise if the test icon is a Crown...
		else if ( testIcon == ICON_CROWN )
		{
			// then we still have a substitution.  In this case the line
			// started out with a Crown.
			bSubstitution = true;

			// We have now found our first icon that is not a Crown.  All
			// of the rest of the icons will have to match this one now for the
			// streak to continue, so change our test icon.
			testIcon = currentIcon;
			continue;
		}

		// If the current icon is not the test icon...
        if ( currentIcon != testIcon )
        {
			// then the streak is over so break out of the loop
			break;
        }
    }

	// If we made it all the way through and the testIcon is still a crown...
	if ( testIcon == ICON_CROWN )
	{
		// then this must be a 5 crown win, so reset the substitution flag.
		bSubstitution = false;
	}

	// Use the array to look up the spin result for i testIcons.
	return lookupLineWinSpinResult( testIcon, i );
}

bool RealmOfRichesGuts::doesCrownLineWinPayMore( SpinResult srCrown,
	SpinResult srOther ) const
{
	// Lookup the payout for the Crown line win.
	long nCrownLineWinPayout = getPayout( srCrown )->payoutAmount;

	// Lookup the payout for the other line win.
	long nOtherLineWinPayout = getPayout( srOther )->payoutAmount;

	// Return true if the Crown payout is bigger.
    return ( nCrownLineWinPayout > nOtherLineWinPayout );
}

void RealmOfRichesGuts::evaluateScatterWin( SlotSpin* spin, SpinResult srScatterResult, int32 scatterPositions )
{
	// If we got the scatter win (or almost got it)
	if ( srScatterResult != EVT_LOSER )
	{
		// Initialize the multiplier.
		int32 multiplier = 1;

		// Get the base payout for the scatter.
		int32 nPayout = getPayout( srScatterResult )->payoutAmount;
		
		// Scatters payout based on the total bet, so factor in the number of bet lines.
		nPayout *= spin->getSpinLineCount();

		// Add the payout (with multiplier) to the total win for this spin.
		increaseTotalWin( nPayout * multiplier );
    
		// Add a scatter to the spin.
		SlotScatter* pScatter = spin->addScatter( scatterPositions,
			nPayout * getBetPerLine(), multiplier, false, srScatterResult, 0 );

		// If the free spin multiplier was used...
		if ( multiplier == MULTIPLIER_FREE_SPIN )
		{
			// then add the free spin note.
			pScatter->addNote( NOTE_FREE_SPIN );
		}
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 RealmOfRichesGuts::evaluateFeatureTrigger()
///
/// This function determines if the current spin triggers the free game
///	feature and adds the scatter.
////////////////////////////////////////////////////////////////////////////
void RealmOfRichesGuts::evaluateFeatureTrigger( SlotSpin* spin, SpinResult srScatterResult, int32 scatterPositions)
{
	// If we are in re-spin mode...
	if ( getGameModeId() == MODE_RESPIN )
	{
		// then see if they triggered the free game feature.
		if ( lookupScatterIconCount( srScatterResult ) >= 3 )
		{
			// They triggered the free spin feature.
			// Make sure we are in free spin mode.
			setGameModeId( MODE_FREE_SPIN );

			// See how many games they get.
			int32 nFreeSpins = 0;

			switch( srScatterResult )
			{
			case EVT_THREE_SHIELD:
				nFreeSpins = 10;
				break;
			case EVT_FOUR_SHIELD:
				nFreeSpins = 15;
				break;
			case EVT_FIVE_SHIELD:
				nFreeSpins = 25;
				break;
			}

			// Add the free spins.
			incrementFreeSpins( nFreeSpins );

			// Add a scatter to the spin for the feature trigger.
			spin->addScatter( scatterPositions, 0, 0, false,
				EVT_FREE_GAME_FEATURE, nFreeSpins );
		}
		// Otherwise...
		else
		{
			// if we still will have free spins after this re-spin...
			if ( getFreeSpins() > 1 )
			{
				// then switch back to free spin mode so that we don't play the
				// remaining free spins as re-spins.
				setGameModeId( MODE_FREE_SPIN );
			}

			// If we had at least one scatter icon...
			if( srScatterResult == EVT_TWO_SHIELD  )
			{
				// then add a scatter to the spin for the feature near miss.
				spin->addScatter( scatterPositions, 0, 0, false,
					EVT_FEATURE_NEAR_MISS, 0 );
			}
		}
	}
	// Otherwise...
	else
	{
		// see if they triggered the re-spin feature.
		if ( lookupScatterIconCount( srScatterResult ) >= 2 )
		{
			// They triggered the re-spin feature.
			// Make sure we are in re-spin mode.
			setGameModeId( MODE_RESPIN );

			// Add the re-spins.
			incrementFreeSpins( 1 );

			// We need to see which reels had scatters on them.
			// This array of masks will extract the scatter position
			// bits for the given reel.  So to see if reel 2 had any
			// scatters on it, just do this:
			//   scatterPositions & nScatterMask[ 2 ]
			int32 nScatterMask[] = 
			{
				SCATTER_REEL_0_MASK,
				SCATTER_REEL_1_MASK,
				SCATTER_REEL_2_MASK,
				SCATTER_REEL_3_MASK,
				SCATTER_REEL_4_MASK
			};

			// Make sure we have an entry in the scatter mask array
			// for each reel in the game.
			ASSERT( countof( nScatterMask ) == getReelCount() );

			// An extra check in debug builds.
			#ifdef _DEBUG
				uint8 nReelsHeld = 0;
			#endif

			// Get the stops for the spin.
			const uint8* pStops = spin->getStops();

			// Loop through all of the reels.
			for ( uint8 n = 0; n < getReelCount(); n++ )
			{
				// If this reel has a scatter icon on it...
				if ( scatterPositions & nScatterMask[ n ] )
				{
					// Then set the hold stop to be the current stop for the reel.
					setReelHoldStop( n, pStops[ n ] );

					// An extra check in debug builds.
					#ifdef _DEBUG
						nReelsHeld++;
					#endif
				}
			}

			// Make sure that we found at least 2 reels that are held.
			ASSERT( nReelsHeld >= 2 );

			// Sanity check.
			ASSERT( nReelsHeld <= getReelCount() );

			// Add a scatter to the spin for the feature trigger.
			spin->addScatter( scatterPositions, 0, 0, false,
				EVT_RESPIN_FEATURE, 1 );
		}
		// Otherwise...
		else
		{
			// TODO !!!!
			// if we had at least one scatter icon...
			if ( lookupScatterIconCount( srScatterResult ) > 0 )
			{
				// then add a scatter to the spin for the feature near miss.
				spin->addScatter( scatterPositions, 0, 0, false,
					EVT_FEATURE_NEAR_MISS, 0 );

				// We should never have 2 icons if we add a near miss.
				ASSERT( lookupScatterIconCount( srScatterResult ) < 2 );
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 RealmOfRichesGuts::resetReelHoldStops()
///
/// This function resets all of the reel hold stops in preparation for a
/// new spin.
////////////////////////////////////////////////////////////////////////////
void RealmOfRichesGuts::resetReelHoldStops()
{
	// Just set the sub-game data back to -1.
    m_subGame->update( SGDIDX_REEL_HOLD_STOP_1, -1 );
    m_subGame->update( SGDIDX_REEL_HOLD_STOP_2, -1 );
    m_subGame->update( SGDIDX_REEL_HOLD_STOP_3, -1 );
    m_subGame->update( SGDIDX_REEL_HOLD_STOP_4, -1 );
    m_subGame->update( SGDIDX_REEL_HOLD_STOP_5, -1 );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 RealmOfRichesGuts::resetFreeSpinCrownSubstitutions()
///
/// This function resets all of the reel hold stops in preparation for a
/// new spin.
////////////////////////////////////////////////////////////////////////////
void RealmOfRichesGuts::resetFreeSpinCrownSubstitutions()
{
	// Just set the sub-game data back to 0.
    m_subGame->update( SGDIDX_REEL_SUBST_CROWN_1, -1 );
    m_subGame->update( SGDIDX_REEL_SUBST_CROWN_2, -1 );
    m_subGame->update( SGDIDX_REEL_SUBST_CROWN_3, -1 );
    m_subGame->update( SGDIDX_REEL_SUBST_CROWN_4, -1 );
    m_subGame->update( SGDIDX_REEL_SUBST_CROWN_5, -1 );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 RealmOfRichesGuts::getReelHoldStop()
///
/// Accessor function to get the stop position to hold for the passed in
/// reel.
////////////////////////////////////////////////////////////////////////////
int32 RealmOfRichesGuts::getReelHoldStop( uint8 nReel )
{
	// Simple bounds check.
	ASSERT( nReel < getReelCount() );

	// Just return the sub-game data for the reel.
    return m_subGame->getData( SGDIDX_REEL_HOLD_STOP_1 + nReel );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 RealmOfRichesGuts::getFreeSpinCrownSubstitution( uint8 nReel )
///
/// Accessor function to get the stop position to substitute with a crown
/// during free spins.
////////////////////////////////////////////////////////////////////////////
int32 RealmOfRichesGuts::getFreeSpinCrownSubstitution( uint8 nReel ) const
{
	// Simple bounds check.
	ASSERT( nReel < getReelCount() );

	// Just return the sub-game data for the reel.
    return m_subGame->getData( SGDIDX_REEL_SUBST_CROWN_1 + nReel );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 RealmOfRichesGuts::setReelHoldStop()
///
/// Accessor function to set the stop position to hold for the passed in
/// reel.
////////////////////////////////////////////////////////////////////////////
void RealmOfRichesGuts::setReelHoldStop( uint8 nReel, int32 nStop )
{
	// Simple bounds check.
	ASSERT( nReel < getReelCount() );

	// Update the sub-game data.
    m_subGame->update( SGDIDX_REEL_HOLD_STOP_1 + nReel, nStop );

	// If we are holding this reel...
	if ( nStop != -1 )
	{
		// then log it in the feature data for an audit trail.
		m_feature->update( SGDIDX_REEL_HOLD_STOP_1 + nReel, nStop, true );
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 RealmOfRichesGuts::setFreeSpinCrownSubstitution()
///
/// Accessor function to set the stop position to hold for the passed in
/// reel.
////////////////////////////////////////////////////////////////////////////
void RealmOfRichesGuts::setFreeSpinCrownSubstitution( uint8 nReel, int32 nSubstitute )
{
	// Simple bounds check.
	ASSERT( nReel < getReelCount() );

    // Only really useful to call this during FREE SPIN mode
    ASSERT( getGameModeId() == MODE_FREE_SPIN );

	// Update the sub-game data.
    m_subGame->update( SGDIDX_REEL_SUBST_CROWN_1 + nReel, nSubstitute );

	// If we are substituting on this reel...
	if ( nSubstitute != 0 )
	{
		// then log it in the feature data for an audit trail.
		m_feature->update( SGDIDX_REEL_SUBST_CROWN_1 + nReel, nSubstitute, true );
	}
}


void RealmOfRichesGuts::preSpinClassifyResults( SlotSpin* spin )
{
	SlotGuts::preSpinClassifyResults(spin);

    // not until here is it ok to tell the world about icons we're going to swap out.
	m_bAllowCrownSubstitutions = true;

    resetFreeSpinCrownSubstitutions();
		
	// If we are not in re-spin mode...
	if ( getGameModeId() != MODE_RESPIN )
	{
		// then reset all of the reel hold stops.
		resetReelHoldStops();

        // Then we need to look at the stops to see if
        // any are crowns.
        if ( getGameModeId() == MODE_FREE_SPIN )
        {            
            // Loop through all of the reels.
            for ( uint8 reel = 0; reel < getReelCount(); reel++ )
            {
                for ( uint8 row = 0 ; row < 3 ; ++row )
                {
                    // Get the current stop.
                    uint8 stop = relativeWheelPosition( MODE_FREE_SPIN, reel,
                                                        spin->getStops()[ reel ], row );

                    int32 nIcon = getIcon( MODE_FREE_SPIN, reel, stop )->iconid;
                    
                    // If this has a crown
                    if ( nIcon == ICON_CROWN )
                    {
                        setFreeSpinCrownSubstitution( reel, row );
                        break;
                    }
                }
            }
        }
	}
	// Otherwise...
    else
    {
		// we will need to hold some of the reel stops, which
		// means we need to cast away the constness of the stops.
        uint8* pStops = const_cast< uint8* >( spin->getStops() );
		
		// An extra check in debug builds.
		#ifdef _DEBUG
			uint8 nReelsHeld = 0;
		#endif

		// Loop through all of the reels.
		for ( uint8 n = 0; n < getReelCount(); n++ )
		{
			// Get the stop we are supposed to use for this reel, if any.
			int32 nStop = getReelHoldStop( n );

			// If we are holding this reel at a specific stop...
			if ( nStop != -1 )
			{
				// then store the stop in the spin.
				pStops[ n ] = nStop;

				// An extra check in debug builds.
				#ifdef _DEBUG
					nReelsHeld++;
				#endif
			}
		}

		// Make sure that we found at least 2 reels that are held.
		ASSERT( nReelsHeld >= 2 );

		// Sanity check.
		ASSERT( nReelsHeld <= getReelCount() );
    }
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 RealmOfRichesGuts::Debug_SetLoserStops( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// Base class override, returns a losing spin triggered by the debug tool
////////////////////////////////////////////////////////////////////////////
void RealmOfRichesGuts::Debug_SetLoserStops( uint8* pStops )
{
	pStops[0]=0;
	pStops[1]=3;
	pStops[2]=0;
	pStops[3]=0;
	pStops[4]=0;
}